package fiuba.algo3.algoThieft.vista;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.xml.sax.SAXException;

import fiuba.algo3.algoThieft.modelo.Capital;
import fiuba.algo3.algoThieft.modelo.Caracteristica;
import fiuba.algo3.algoThieft.modelo.ErrorNoExisteElPersonaje;
import fiuba.algo3.algoThieft.modelo.ErrorNoSeInicioUnNuevoCaso;
import fiuba.algo3.algoThieft.modelo.ErrorPersonajeNoAsignado;
import fiuba.algo3.algoThieft.modelo.ErrorValorNoValido;
import fiuba.algo3.algoThieft.modelo.ErrorYaExisteElPersonaje;
import fiuba.algo3.algoThieft.modelo.Interpol;
import fiuba.algo3.algoThieft.modelo.Juego;
import fiuba.algo3.algoThieft.modelo.Ladron;
import fiuba.algo3.algoThieft.modelo.Lugar;
import fiuba.algo3.algoThieft.modelo.ObjetoRobado;
import fiuba.algo3.algoThieft.modelo.Personaje;
import fiuba.algo3.algoThieft.modelo.PersonajePolicial;
import fiuba.algo3.algoThieft.modelo.Pista;

public class VistaDeConsola implements Observador{
	
	private final String ERROR_NO_HAY_CASO = "ERROR: no se inicio un nuevo caso";
	private final String ERROR_ARCHIVO_DANIADO = "ERROR: archivos del juego daniados";
	private final String ERROR_GUARDANDO = "ERROR: no se pudo guardar progreso";
	private final String ERROR_YA_EXISTE_PERSONAJE = "ERROR: ya existe el personaje";
	private final String ERROR_NO_EXISTE_PERSONAJE = "ERROR: No existe ese personaje";
	
	
	
	
	private Juego modelo;
	private Consola consola;
	private Menu menuPrincipal;
	private Menu menuDelCaso;
	
	
	
	
	
	public VistaDeConsola(Juego modelo) {
		this.modelo = modelo;
		this.modelo.agregarObservador( this );
		this.consola = new Consola();
		this.menuPrincipal = new Menu ( "Menu Principal", Arrays.asList( "Iniciar perfil" , "Salir" ) );
		this.menuDelCaso = new Menu (Arrays.asList( "Visitar" , "Viajar" , "Generar orden de arresto") );
	}

	
	
	public void iniciar(){
		
    	
		//saludo
		this.consola.mostrarLinea("Bienvenido, estas jugando a AlgoThieft");
		this.menuPrincipal.mostrarEnConsola();
		int eleccion = this.menuPrincipal.opcionElegida();
		if ( eleccion == 1 ){
			this.ingresarNombre();
		}
		this.consola.salir();
}

	
	
	private void ingresarNombre() {
		String linea1 = "Ingresar nombre: ";		
		this.consola.mostrar( linea1 );			
		String nombre = this.consola.obtenerIngreso();
		PersonajePolicial personaje = new Personaje( nombre );
		
		if (this.modelo.existePersonaje(personaje)){
			
			try {
				this.modelo.utilizarPersonaje(personaje);
			} catch (ErrorNoExisteElPersonaje e) {
				this.consola.mostrarLinea(this.ERROR_NO_EXISTE_PERSONAJE);;
			}
			this.inicioDePerfil();
				
		}else{
			
			Pregunta pregunta = new Pregunta("no existe un personaje que se llame "+ nombre + "!!!" , "Desea crearlo");
			
			if ( pregunta.obtenerRespuesta() ){
				//crear Personaje
				try {
					this.modelo.agregarPersonaje(personaje);
				} catch (ErrorYaExisteElPersonaje e1) {
					this.consola.mostrarLinea(this.ERROR_YA_EXISTE_PERSONAJE);
				}
				try {
					this.modelo.utilizarPersonaje(personaje);
				} catch (ErrorNoExisteElPersonaje e) {
					this.consola.mostrarLinea(this.ERROR_NO_EXISTE_PERSONAJE);
				}
				this.inicioDePerfil();

			}else{
				//si no crea el personaje vuelve al menu principal
				this.iniciar();
			}
				
		}
		
		
		
	}
	
	
	private void inicioDePerfil() {
		this.consola.mostrarLinea("hola " + this.modelo.getPersonajeActual().getNombre());
		this.consola.mostrarLinea( "tu rango actual es "+ this.modelo.getPersonajeActual().rangoComoString() );
		this.nuevoCaso();
	}
	
	
	
	private void nuevoCaso() {
		
		try {
			this.modelo.iniciarCaso();
			ObjetoRobado objetoRobado = this.modelo.obtenerObjetoRobado();
			this.consola.mostrarLinea("Han robado " + objetoRobado.getNombre() + " en la ciudad de "
					+ objetoRobado.getUbicacionInicial().getNombre());
			this.consola.mostrarLinea("el sospechoso es de sexo " + this.modelo.getSexoDelLadron() );
			this.consola.mostrarLinea("presione enter para continuar");
			this.consola.obtenerIngreso();
			
			this.navegarEnMenuDelCaso();					
			
			
		} catch (SAXException e) {
			this.consola.mostrarLinea( this.ERROR_ARCHIVO_DANIADO );
		} catch (IOException e) {
			this.consola.mostrarLinea( this.ERROR_ARCHIVO_DANIADO );
		} catch (ParserConfigurationException e) {
			this.consola.mostrarLinea( this.ERROR_ARCHIVO_DANIADO );
		}catch ( ErrorNoSeInicioUnNuevoCaso e){
			this.consola.mostrarLinea( this.ERROR_NO_HAY_CASO );
		} catch (ErrorPersonajeNoAsignado e) {
			e.printStackTrace();
		}
		
				
		
	}

	private void navegarEnMenuDelCaso() {
		
		while ( this.modelo.estaInvestigandoUncaso() ){
			this.menuDelCaso.setTitulo( this.modelo.getTiempoComoString() );
			this.menuDelCaso.mostrarEnConsola();
			int opcionElegida = this.menuDelCaso.opcionElegida();
			switch ( opcionElegida ){
				case 1:
					//visitar
					this.navegarEnMenuVisitar();
					break;
				case 2:
					//viajar		
					this.navegarEnMenuViajar();
		            break;
				case 3:
					//generar orden de arresto
					if ( this.modelo.ordenDeArrestoEmitida() ){
						this.consola.mostrar("YA EMITISTE UNA ORDEN DE ARRESTO");
					}else{
						this.generarOrdenDeArresto();
					}					
		            break;
		     			     
			}
		}
		
	}



	private void generarOrdenDeArresto()  {
		String sexo = this.ingresarCaracteristica( "sexo" );
		String hobby = this.ingresarCaracteristica( "hobby" );
		String cabello = this.ingresarCaracteristica( "cabello" );
		String senia = this.ingresarCaracteristica( "senia" );
		String vehiculo = this.ingresarCaracteristica( "vehiculo" );
		try {
			List<Ladron> resultado = this.modelo.gestionarEmisionDeOrdenDeArresto(sexo, hobby, cabello, senia, vehiculo);
			if ( resultado.size() == 0 ){
				this.consola.mostrarLinea("ningun sospechoso cumple con esas caracteristica");
			}else{
				this.consola.mostrarLinea("Sospechosos:");
				for (Ladron ladron : resultado){
					this.consola.mostrarLinea( ladron.getNombre() );
				}								
			}
			if ( this.modelo.ordenDeArrestoEmitida() ){
				this.consola.mostrarLinea("Emitiendo orden de arresto");
			}
			this.consola.mostrarLinea("Presione enter para continuar");
			this.consola.obtenerIngreso();
			
		} catch (ErrorNoSeInicioUnNuevoCaso e) {
			this.consola.mostrarLinea(ERROR_NO_HAY_CASO);;
		}		
		
	}



	private String ingresarCaracteristica(String cadena) {
		this.consola.mostrar( "Ingrese el " + cadena + ":");
		String valorIngresado = this.consola.obtenerIngreso();
		if ( valorIngresado.equals( "" ) ){
			return valorIngresado;
		}
			else{
			try {			
				@SuppressWarnings("unused")
				// agrego el suppress porque solo lo uso para
				// validar el ingreso
				Caracteristica caracteristica = new Caracteristica( cadena , valorIngresado );						
			} catch (ErrorValorNoValido e) {
				this.consola.mostrarLinea("ERROR: valor invalido");				
				return this.ingresarCaracteristica(cadena);
			}
			//si no da error, el valor ingresado es valido
		return valorIngresado;
		}
			
		
	}



	private void navegarEnMenuViajar() {
		
		PersonajePolicial personaje = this.modelo.getPersonajeActual();
		List<Capital> capitales = personaje.getUbicacion().getCapitalesAdyacentes();
		Collections.shuffle( capitales );
		ArrayList<String> nombresDeCapitales = new ArrayList<String>();
		for ( Capital capital : capitales ){
			nombresDeCapitales.add( capital.getNombre() );		
		}
		nombresDeCapitales.add("Volver al menu anterior");
		Menu menuLugares = new Menu( "A donde quieres viajar?" , nombresDeCapitales );
		menuLugares.mostrarEnConsola();
		
		int opcionElegida = menuLugares.opcionElegida();
		
		if ( opcionElegida < 4 ) {
			//selecciono una capital para viajar
			try {

				this.modelo.gestionarViaje( capitales.get( opcionElegida - 1 ) );

			} catch (ErrorNoSeInicioUnNuevoCaso e) {
				this.consola.mostrarLinea( this.ERROR_NO_HAY_CASO );;
			}			
		}
		// despues de viajar al lugar elegido
		// o si elige volver, regresa al menu del caso
			
		
	}
		
	



	private void navegarEnMenuVisitar() {
		
		PersonajePolicial personaje = this.modelo.getPersonajeActual();
		List<Lugar> lugares = personaje.getUbicacion().getLugares();		
		ArrayList<String> nombresDeLugares = new ArrayList<String>();
		for ( Lugar lugar : lugares ){
			nombresDeLugares.add( lugar.getNombre() );		
		}
		nombresDeLugares.add("Volver al menu anterior");
		Menu menuLugares = new Menu( "Que edificio quieres visitar?" , nombresDeLugares	);
		menuLugares.mostrarEnConsola();
		
		int opcionElegida = menuLugares.opcionElegida();
		
		if ( opcionElegida < 4 ) {
			//selecciono un lugar para visitar
			try {
				Pista unaPista = this.modelo.gestionarVisita(lugares.get(opcionElegida - 1 ) );
				this.consola.mostrar( unaPista );
			} catch (ErrorNoSeInicioUnNuevoCaso e) {
				this.consola.mostrarLinea( this.ERROR_NO_HAY_CASO );;
			}			
		}
		// despues de mostrar la pista del lugar elegido
		// o si elige volver, regresa al menu del caso
			
		this.navegarEnMenuDelCaso();
		
		
	}
	
	
	
	@Override
	public void actualizar() {
		// se actualiza cuando por algun motivo
		// se termino el caso
		// mostrar algo dependiendo del estado del caso
		int caso = this.modelo.estadoDeLaInvestigacion();
		switch ( caso ){
		
		case Interpol.TIEMPO_AGOTADO:
			this.consola.mostrarLinea("Has tardado demasiado, se te agoto el tiempo");			
			break;
			
		case Interpol.ORDEN_ARRESTO_INCORRECTA:			
			this.consola.mostrarLinea("La interpol no pudo capturar al ladron");
			this.consola.mostrarLinea("la orden de arresto es incorrecta");
            break;
		case Interpol.LADRON_ATRAPADO:
			this.consola.mostrarLinea("Felicitaciones, gracias a tu ayuda la interpol pudo atrapar al ladron");
            break;		     
	
		}
				
		try {					
			this.modelo.guardarAvances();
			} 
		catch (ParserConfigurationException e) {
			this.consola.mostrarLinea(this.ERROR_GUARDANDO);
			}
		catch (TransformerException e) {
				this.consola.mostrarLinea(this.ERROR_GUARDANDO);
			}
			
		
		Pregunta otroCaso = new Pregunta("El caso concluyo" , "Estas preparado para comenzar otro caso");
		if (otroCaso.obtenerRespuesta()){
			this.nuevoCaso();
		}
		
		// si no quiere otro caso se regresa al menu principal		
		this.iniciar();
			
	}

	
}
